package facade

import (
	"fmt"
	"time"
)

// 外面模式示例
// 假设我们有一个电商平台的订单处理系统，包含多个复杂子系统：
// 库存管理
// 支付处理
// 物流配送
// 通知服务
// 客户下单需要协调这些子系统，外观模式可以提供一个统一的接口简化这个过程。

// InventorySystem 子系统-库存管理
type InventorySystem struct {
}

// CheckStock 检查库存
func (i *InventorySystem) CheckStock(productID string, quantity int) bool {
	// 检查库存逻辑
	fmt.Printf("检查产品 %s 的库存，数量：%d\n", productID, quantity)
	return true
}

func (i *InventorySystem) ReserveStock(productID string, quantity int) bool {
	fmt.Printf("库存系统: 预留商品 %s，数量 %d\n", productID, quantity)
	// 模拟预留库存
	return true
}

func (i *InventorySystem) ReleaseStock(productID string, quantity int) {
	fmt.Printf("库存系统: 释放商品 %s 的预留库存，数量 %d\n", productID, quantity)
}

// PaymentSystem 子系统-支付处理
type PaymentSystem struct {
}

// ProcessPayment 处理支付
func (p *PaymentSystem) ProcessPayment(orderID string, amount float64) bool {
	fmt.Printf("支付系统: 处理订单 %s，金额 %.2f\n", orderID, amount)
	// 模拟支付处理
	return true
}

func (p *PaymentSystem) RefundPayment(orderID string, amount float64) bool {
	fmt.Printf("支付系统: 处理订单 %s 的退款，金额 ¥%.2f\n", orderID, amount)
	return true
}

// ShippingSystem 子系统-物流配送
type ShippingSystem struct {
}

func (s *ShippingSystem) ScheduleDelivery(orderID string, address string) string {
	fmt.Printf("物流系统: 为订单 %s 安排配送，地址: %s\n", orderID, address)
	// 模拟生成运单号
	trackingNumber := fmt.Sprintf("TRACK-%d", time.Now().Unix())
	return trackingNumber
}

func (s *ShippingSystem) CancelDelivery(trackingNumber string) bool {
	fmt.Printf("物流系统: 取消配送，运单号 %s\n", trackingNumber)
	return true
}

// ========= 子系统：通知服务 =========
type NotificationSystem struct{}

func (n *NotificationSystem) SendEmail(to, subject, body string) {
	fmt.Printf("通知系统: 发送邮件给 %s\n主题: %s\n内容: %s\n", to, subject, body)
}

func (n *NotificationSystem) SendSMS(to, message string) {
	fmt.Printf("通知系统: 发送短信给 %s\n内容: %s\n", to, message)
}

// OrderServiceFacade 外观-订单服务
type OrderServiceFacade struct {
	inventory    *InventorySystem
	payment      *PaymentSystem
	shipping     *ShippingSystem
	notification *NotificationSystem
}

func NewOrderServiceFacade() *OrderServiceFacade {
	return &OrderServiceFacade{
		inventory:    &InventorySystem{},
		payment:      &PaymentSystem{},
		shipping:     &ShippingSystem{},
		notification: &NotificationSystem{},
	}
}

// 下单接口
func (o *OrderServiceFacade) PlaceOrder(orderID, userID, productID string, quantity int, amount float64, paymentMethod, address, email, phone string) bool {
	fmt.Println("\n======= 开始处理下单 =======")

	// 1. 检查库存
	if !o.inventory.CheckStock(productID, quantity) {
		fmt.Println("错误: 库存不足")
		return false
	}

	// 2. 预留库存
	if !o.inventory.ReserveStock(productID, quantity) {
		fmt.Println("错误: 库存预留失败")
		return false
	}

	// 3. 处理支付
	if !o.payment.ProcessPayment(orderID, amount) {
		fmt.Println("错误: 支付处理失败")
		o.inventory.ReleaseStock(productID, quantity) // 释放预留库存
		return false
	}

	// 4. 安排配送
	trackingNumber := o.shipping.ScheduleDelivery(orderID, address)

	// 5. 发送通知
	emailSubject := "您的订单已确认"
	emailBody := fmt.Sprintf("感谢您的购买！订单号: %s\n商品: %s x%d\n总金额: ¥%.2f\n运单号: %s",
		orderID, productID, quantity, amount, trackingNumber)
	o.notification.SendEmail(email, emailSubject, emailBody)

	smsMessage := fmt.Sprintf("订单 %s 已确认，运单号: %s", orderID, trackingNumber)
	o.notification.SendSMS(phone, smsMessage)

	fmt.Println("======= 下单处理完成 =======")
	return true
}

// 取消订单接口
func (o *OrderServiceFacade) CancelOrder(orderID, productID string, quantity int, amount float64, trackingNumber, email, phone string) bool {
	fmt.Println("\n======= 开始取消订单 =======")
	
	// 1. 释放库存
	o.inventory.ReleaseStock(productID, quantity)
	
	// 2. 处理退款
	if !o.payment.RefundPayment(orderID, amount) {
		fmt.Println("警告: 退款处理失败，需要人工介入")
	}
	
	// 3. 取消配送
	if !o.shipping.CancelDelivery(trackingNumber) {
		fmt.Println("警告: 配送取消失败，需要人工介入")
	}
	
	// 4. 发送通知
	emailSubject := "您的订单已取消"
	emailBody := fmt.Sprintf("订单 %s 已取消\n退款金额: ¥%.2f\n运单号: %s 已取消", 
		orderID, amount, trackingNumber)
	o.notification.SendEmail(email, emailSubject, emailBody)
	
	smsMessage := fmt.Sprintf("订单 %s 已取消，退款金额 ¥%.2f", orderID, amount)
	o.notification.SendSMS(phone, smsMessage)
	
	fmt.Println("======= 订单取消完成 =======")
	return true
}